package item08;

import java.awt.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Test01 {

    private static final Set<Point02> unitCircle;

    static {
        unitCircle = new HashSet<Point02>();
        unitCircle.add(new Point02(1, 0));
        unitCircle.add(new Point02(0, 1));
        unitCircle.add(new Point02(-1, 0));
        unitCircle.add(new Point02(0, -1));
    }

    //在不在圆里
    public static boolean onUnitCircle(Point02 p) {
        return unitCircle.contains(p);
    }

    public static void main(String[] args) {

        // 自反性 reflexivity
        // X x = new X();
        // list.add(x);
        // list.contains(x); false 这就是违反自反性的后果

        // 对称性
        CaseInsensitiveString01 cis = new CaseInsensitiveString01("Polish");
        String s = "polish";
        System.out.println(cis.equals(s));
        System.out.println(s.equals(cis));
        List<CaseInsensitiveString01> list = new ArrayList<CaseInsensitiveString01>();
        list.add(cis);
        // 在sun的当前实现中，它碰项返回false,但这只是这个特定实现得出的结果而已
        System.out.println(list.contains(s));
        //一旦违反了equals约定，当其他对象面对你的对象时，你完全不知道这些对象的行为会怎么样。

        // point colorPoint
        // 1使用继承过来的equals方法，color被忽略
        Point01 point01 = new Point01(1, 2);
        ColorPoint01 cp01 = new ColorPoint01(1, 2, Color.RED);
        System.out.println(point01.equals(cp01));
        System.out.println(cp01.equals(point01));

        // 违反了对称性
        ColorPoint02 cp02 = new ColorPoint02(1, 2, Color.RED);
        System.out.println(point01.equals(cp02));
        System.out.println(cp02.equals(point01));

        // 违反了传递性
        ColorPoint03 cp03 = new ColorPoint03(1, 2, Color.RED);
        ColorPoint03 cp04 = new ColorPoint03(1, 2, Color.BLUE);
        System.out.println(point01.equals(cp03));
        System.out.println(cp03.equals(point01));
        System.out.println(cp04.equals(point01));
        System.out.println(cp03.equals(cp04));

        // 无法在扩展可实例化的类的同时，既增加新的值组件，同时又保留equals约定
        // 除非愿意放弃面向对象的抽象所带来的优势


        // 结果无法接受
        Point02 point02 = new Point02(1, 2);
        ColorPoint02 colorPoint02 = new ColorPoint02(1, 2, Color.RED);
        System.out.println(point02.equals(colorPoint02));
        System.out.println(colorPoint02.equals(point02));
        // 里氏替换原则
        // hashset 里调用了对象的equals方法
        // 但是这样对于需求来说是不对的
        CounterPoint counterPoint = new CounterPoint(1, 0);
        System.out.println(onUnitCircle(counterPoint));


        /**
         * @see java.sql.Timestamp#equals(Object) 违反了对称性
         * Date timestamp 不要混合在一起使用
         */
        // 可以在一个抽象类的子类中增加新的组件，而不会违反equals约定

        // 一致性
        // 相等的对象永远相等，不相等的对象永远不相等
        // 无论类是否是不可变的，都不要使equals方法依赖于不可靠的资源。

        // 非空性
        // 所有对象都必须不等于null。通用约定不允许抛出nullPointerException异常
        // 通常做法
        Point03 point03 = new Point03(1, 2);
        System.out.println(point03.equals(null));
        // o instanceof Point03 如果o为null会返回false


        // 实现高质量equals方法的诀窍
        // 1.使用==操作符检查“参数是否为这个对象的引用”
        // 2.使用instanceof操作符检查“参数是否正确的类型”
        // 3.把参数转换正确的类型
        // 4.对于该类中的每个“关键域”，检查参数中的域是否与该对象中对应的域相匹配
        // 5.当你编写完成了equals方法后，应该问自己三个问题：它是否是对称性的、传递性的、一致性的
        // 写单元测试类测试


        // 覆盖equals时总要覆盖hashCode
        // 不要企图让equals方法过于智能(注：简单点挺好的)
        // 不要将equals声明中的object对象替换为其他的类型
        // 使用@Override


    }

}
